﻿using DoNet.Bpmn.Core.Enums;
using DoNet.Bpmn.Core.Utils;
using DoNet.Bpmn.Core.Vo;
using DoNet.Bpmn.IServices;
using DoNet.Bpmn.Models;
using DoNet.Bpmn.Services;

namespace DoNet.Bpmn.Adaptor.BpmnNode
{
    public class NodePropertyPersonnelAdaptor : BpmnNodeAdaptor
    {
        private readonly IBpmnNodePersonnelConfigService _bpmnNodePersonnelConfigService;
        private readonly BpmnNodePersonnelEmplConfigService _bpmnNodePersonnelEmplConfigService;
        private readonly IBpmnEmployeeInfoProviderService _bpmnEmployeeInfoProviderService;

        public NodePropertyPersonnelAdaptor(
            BpmnNodePersonnelConfigService bpmnNodePersonnelConfigService,
            BpmnNodePersonnelEmplConfigService bpmnNodePersonnelEmplConfigService,
            IBpmnEmployeeInfoProviderService bpmnEmployeeInfoProviderService
            )
        {
            _bpmnNodePersonnelConfigService = bpmnNodePersonnelConfigService;
            _bpmnNodePersonnelEmplConfigService = bpmnNodePersonnelEmplConfigService;
            _bpmnEmployeeInfoProviderService = bpmnEmployeeInfoProviderService;
        }
        public override BpmnNodeVo? FormatToBpmnNodeVo(BpmnNodeVo bpmnNodeVo)
        {
            BpmnNodePersonnelConfig bpmnNodePersonnelConfig = _bpmnNodePersonnelConfigService.GetByBpmnNodeId(bpmnNodeVo.Id);
            if (bpmnNodePersonnelConfig == null)
            {
                throw new Exception($"未能根据节点id: {bpmnNodeVo.Id}查到指定人员信息!");
            }
            List<string> emplIds = new List<string>();
            List<string> emplNames = new List<string>();
            IEnumerable<BpmnNodePersonnelEmplConfig> bpmnNodePersons = _bpmnNodePersonnelEmplConfigService.GetListByBpmnNodePersonneId(bpmnNodePersonnelConfig.Id);
            if (ObjectUtils.IsEmpty(bpmnNodePersons))
            {
                throw new Exception("配置错误或者数据被删除,指定员人审批未获取到人员");
            }
            foreach (var bpmnNodePersonnelEmplConf in bpmnNodePersons)
            {
                string emplId = bpmnNodePersonnelEmplConf.EmplId;
                string emplName = bpmnNodePersonnelEmplConf.EmplName;
                emplIds.Add(emplId);
                if (!string.IsNullOrEmpty(emplName))
                {
                    emplNames.Add(emplName);
                }
            }

            bpmnNodeVo.Property = new BpmnNodePropertysVo
            {
                SignType = bpmnNodePersonnelConfig.SignType,
                EmplIds = emplIds,
                EmplList = GetEmplList(emplIds, emplNames)
            };
            return bpmnNodeVo;
        }

        public override void EditBpmnNode(BpmnNodeVo bpmnNodeVo)
        {
            var bpmnNodePropertysVo = bpmnNodeVo.Property ?? new BpmnNodePropertysVo();

            var bpmnNodePersonnelConfig = new BpmnNodePersonnelConfig
            {
                BpmnNodeId = (int)bpmnNodeVo.Id,
                SignType = bpmnNodePropertysVo.SignType ?? 0,
                CreatorTime = DateTime.Now,
                //CreatorUserId = SecurityUtils.GetLogInEmpNameSafe(),
                LastModifyTime = DateTime.Now,
                //LastModifyUserId = SecurityUtils.GetLogInEmpNameSafe()
            };

            _bpmnNodePersonnelConfigService.Insert(bpmnNodePersonnelConfig);
            long nodePersonnelId = bpmnNodePersonnelConfig.Id;

            if (bpmnNodePropertysVo.EmplIds == null || !bpmnNodePropertysVo.EmplIds.Any())
            {
                return;
            }

            var personnelEmplConfigs = new List<BpmnNodePersonnelEmplConfig>();
            var emplList = bpmnNodePropertysVo.EmplList ?? new List<BaseIdTranStruVo>();
            var id2nameMap = emplList.ToDictionary(x => x.Id, x => x.Name, StringComparer.Ordinal);

            foreach (var emplId in bpmnNodePropertysVo.EmplIds)
            {
                var personnelEmplConfig = new BpmnNodePersonnelEmplConfig
                {
                    BpmnNodePersonneId = nodePersonnelId,
                    EmplId = emplId,
                    CreatorTime = DateTime.Now,
                    //CreatorUserId = SecurityUtils.GetLogInEmpNameSafe(),
                    LastModifyTime = DateTime.Now,
                    //LastModifyUserId = SecurityUtils.GetLogInEmpNameSafe(),
                    EmplName = id2nameMap.ContainsKey(emplId) ? id2nameMap[emplId] : string.Empty
                };

                personnelEmplConfigs.Add(personnelEmplConfig);
            }

            _bpmnNodePersonnelEmplConfigService.Insert(personnelEmplConfigs);
        }

        /// <summary>
        /// Get employee list.
        /// If emplNames is not empty, it is stored in the database and then loaded.
        /// </summary>
        /// <param name="emplIds">List of employee IDs.</param>
        /// <param name="emplNames">List of employee names.</param>
        /// <returns>List of BaseIdTranStruVo objects.</returns>
        private List<BaseIdTranStruVo> GetEmplList(List<string> emplIds, List<string> emplNames)
        {
            var result = new List<BaseIdTranStruVo>();

            if (emplNames != null && emplNames.Any())
            {
                if (emplIds.Count != emplNames.Count)
                {
                    throw new Exception("指定人员审批存在姓名不存在的人员!");
                }

                for (int i = 0; i < emplIds.Count; i++)
                {
                    var vo = new BaseIdTranStruVo
                    {
                        Id = emplIds[i],
                        Name = emplNames[i]
                    };
                    result.Add(vo);
                }

                return result;
            }

            var employeeInfos = _bpmnEmployeeInfoProviderService.ProvideEmployeeInfo(emplIds);

            foreach (var emplId in emplIds)
            {
                var vo = new BaseIdTranStruVo
                {
                    Id = emplId,
                    Name = employeeInfos.TryGetValue(emplId, out var empName) ? empName : string.Empty
                };
                result.Add(vo);
            }

            return result;
        }

        public override void SetSupportBusinessObjects()
        {
            ((IAdaptorService)this).AddSupportBusinessObjects(
                BpmnNodeAdpConfigEnum.ADP_CONF_NODE_PROPERTY_PERSONNEL,
                BpmnNodeAdpConfigEnum.ADP_CONF_NODE_TYPE_COPY);
        }
    }
}
